package com.jwds.digital.bios.business.service.service.belt.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jwds.digital.bios.business.core.infrastructure.entity.basic.BasicDevice;
import com.jwds.digital.bios.business.core.infrastructure.entity.belt.BeltDayTargetHis;
import com.jwds.digital.bios.business.core.infrastructure.entity.flow.FlowBasic;
import com.jwds.digital.bios.business.core.infrastructure.mapper.basic.BasicDeviceMapper;
import com.jwds.digital.bios.business.core.infrastructure.mapper.belt.BeltPerformanceMonthMapper;
import com.jwds.digital.bios.business.core.infrastructure.mapper.belt.BeltPerformanceWeekMapper;
import com.jwds.digital.bios.business.core.infrastructure.mapper.belt.BeltRoutePerformanceWeekMapper;
import com.jwds.digital.bios.business.core.infrastructure.mapper.flow.FlowBasicMapper;
import com.jwds.digital.bios.business.core.infrastructure.vo.belt.*;
import com.jwds.digital.bios.business.core.infrastructure.vo.feign.FlowBasicRespVO;
import com.jwds.digital.bios.business.service.service.belt.IBeltDayTargetHisService;
import com.jwds.digital.bios.business.service.service.belt.IBeltRoutePerformanceMonthService;
import com.jwds.digital.bios.business.core.infrastructure.dto.belt.BeltRoutePerformanceMonthReqDTO;
import com.jwds.digital.bios.business.core.infrastructure.dto.belt.assembler.BeltRoutePerformanceMonthAssembler;
import com.jwds.digital.bios.business.core.infrastructure.entity.belt.BeltRoutePerformanceMonth;
import com.jwds.digital.bios.business.core.infrastructure.mapper.belt.BeltRoutePerformanceMonthMapper;
import com.jwds.digital.bios.business.core.exceptions.RecordNotFoundException;
import com.jwds.tdc.framework.application.lib.page.PageRequest;
import com.jwds.tdc.framework.application.lib.page.PageResponse;

import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Year;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 线路效能月表实现类
 * @author 林柏云
 * @date 2024-10-24
 */
@Slf4j
@Service
public class BeltRoutePerformanceMonthServiceImpl extends ServiceImpl<BeltRoutePerformanceMonthMapper, BeltRoutePerformanceMonth> implements IBeltRoutePerformanceMonthService {

  @Autowired
  private BeltRoutePerformanceMonthMapper baseMapper;

  @Autowired
  private IBeltDayTargetHisService beltDayTargetHisService;

  @Override
  public BeltRoutePerformanceMonthRespVO queryById(Long id) {
    if(id == null) {
      return null;
    }
    BeltRoutePerformanceMonth entity = baseMapper.selectById(id);
    return BeltRoutePerformanceMonthAssembler.entity2dto(entity);
  }

  @Override
  public PageResponse<BeltRoutePerformanceMonthRespVO> page(PageRequest<BeltRoutePerformanceMonthReqDTO> request) {
    BeltRoutePerformanceMonthReqDTO condition = request.getQueryCondition();
    Page<BeltRoutePerformanceMonthRespVO> page = new Page<>(request.getPageIndex(), request.getPageSize());
    IPage<BeltRoutePerformanceMonthRespVO> pageData = baseMapper.pageQuery(page, condition);
    return new PageResponse<>((Page<?>)pageData, pageData.getRecords());
  }

  @Override
  public List<BeltRoutePerformanceMonthRespVO> list(BeltRoutePerformanceMonthReqDTO reqDto) {
    return baseMapper.queryList(reqDto);
  }

  @Override
  public void add(BeltRoutePerformanceMonthReqDTO reqDto) {
    BeltRoutePerformanceMonth entity = BeltRoutePerformanceMonthAssembler.dto2entity(reqDto);
    baseMapper.insert(entity);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void batchAdd(List<BeltRoutePerformanceMonthReqDTO> dtoList) {
    dtoList.forEach(this::add);
  }

  @Override
  public void update(BeltRoutePerformanceMonthReqDTO reqDto) {
    BeltRoutePerformanceMonth oldEntity = baseMapper.selectById(reqDto.getId());
    if (oldEntity == null) {
      throw new RecordNotFoundException();
    }
    BeltRoutePerformanceMonth newEntity = BeltRoutePerformanceMonthAssembler.dto2entity(reqDto, oldEntity);
    baseMapper.updateById(newEntity);
  }

  @Override
  public void delete(Long id) {
    BeltRoutePerformanceMonth oldEntity = baseMapper.selectById(id);
    if (oldEntity == null) {
      throw new RecordNotFoundException();
    }
    baseMapper.deleteById(id);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void batchDelete(List<Long> ids) {
    for (Long id : ids) {
      delete(id);
    }
  }
@Autowired
private BeltRoutePerformanceWeekMapper beltRoutePerformanceWeekMapper;

  @Override
  public BeltRoutePerformanceMonthRespVO getLineEfficiencyMonth(Long routeId) {
    // 线路效能月基本信息
    BeltRoutePerformanceMonthRespVO lineEfficiencyMonth = baseMapper.BeltRoutePerformanceMonthRespVO(routeId, 1);

    if (lineEfficiencyMonth == null) {
      return null;
    }

    // 启动空转时间
    BigDecimal startIdleTime = BigDecimal.valueOf(ChronoUnit.MONTHS.between(lineEfficiencyMonth.getStartTime(), lineEfficiencyMonth.getEndTime()));
    lineEfficiencyMonth.setStartIdleTimeInOperation(startIdleTime);

    // 停止空转时间
    BigDecimal endIdleTime = BigDecimal.valueOf(ChronoUnit.MONTHS.between(lineEfficiencyMonth.getStartEmptyTime(), lineEfficiencyMonth.getEndEmptyTime()));
    lineEfficiencyMonth.setEndIdleTimeInOperation(endIdleTime);

    // 运行中空载时间
    lineEfficiencyMonth.setIdleTimeInOperation(lineEfficiencyMonth.getNoLoadRuntime().subtract(startIdleTime).subtract(endIdleTime));

    // 启动空转时间占比
    lineEfficiencyMonth.setStartIdleTimeConsumptionRatio(startIdleTime.divide(lineEfficiencyMonth.getNoLoadRuntime(), 2, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100)));

    // 停止空转时间占比
    lineEfficiencyMonth.setEndIdleTimeConsumptionRatio(endIdleTime.divide(lineEfficiencyMonth.getNoLoadRuntime(), 2, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100)));

    // 运行中空载时间占比
    lineEfficiencyMonth.setInOperationIdleTImeConsumptionRatio(lineEfficiencyMonth.getIdleTimeInOperation().divide(lineEfficiencyMonth.getNoLoadRuntime(), 2, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100)));

    // 运行中空载能耗
    lineEfficiencyMonth.setIdleEnergyInOperation(lineEfficiencyMonth.getNoLoadPowerConsumption().subtract(lineEfficiencyMonth.getStartNoLoadPowerConsumption()).subtract(lineEfficiencyMonth.getEndNoLoadPowerConsumption()));

    // 运行中空载能耗占比
    lineEfficiencyMonth.setInOperationIdleEnergyConsumptionRatio(lineEfficiencyMonth.getIdleEnergyInOperation().divide(lineEfficiencyMonth.getNoLoadPowerConsumption(), 2, BigDecimal.ROUND_HALF_UP));

    // 启动空载能耗占比
    lineEfficiencyMonth.setStartIdleTimeConsumptionRatio(lineEfficiencyMonth.getStartNoLoadPowerConsumption().divide(lineEfficiencyMonth.getNoLoadPowerConsumption(), 2, BigDecimal.ROUND_HALF_UP));

    // 停止空载能耗占比
    lineEfficiencyMonth.setEndIdleTimeConsumptionRatio(lineEfficiencyMonth.getEndNoLoadPowerConsumption().divide(lineEfficiencyMonth.getNoLoadPowerConsumption(), 2, BigDecimal.ROUND_HALF_UP));


    //合格线
    BeltDayTargetHis beltDayTargetHis = beltDayTargetHisService.selectLatest();
    lineEfficiencyMonth.setQualifiedLine(beltDayTargetHis.getWorkEfficiency());

    List<AverageMotorOperatingEfficiencyStats> averageMotorOperatingEfficiencyList =beltRoutePerformanceWeekMapper.getAverageMotorOperatingEfficiencyStats(routeId);
    if (averageMotorOperatingEfficiencyList == null) {
      return null;
    }
    lineEfficiencyMonth.setAverageMotorOperatingEfficiencyStats(averageMotorOperatingEfficiencyList);

/*// 获取上个月的开始时间，即1号 00:00
    LocalDateTime startTime = LocalDateTime.now().minusMonths(1).with(TemporalAdjusters.firstDayOfMonth()).toLocalDate().atStartOfDay();
// 获取上个月的结束时间，即最后一天 23:59:59
    LocalDateTime endTime = LocalDateTime.now().minusMonths(1).with(TemporalAdjusters.lastDayOfMonth())
            .toLocalDate().atTime(23, 59, 59);*/


    // 获取本年的开始时间，即1号 00:00
    LocalDateTime startTime = Year.now().atDay(1).atStartOfDay();
    // 获取本年的结束时间，即12月31日 23:59:59
    LocalDateTime endTime = Year.now().atDay(Year.now().length()).atTime(LocalTime.MAX);


    /* // 获取本月的开始时间，即1号 00:00
    LocalDateTime startTime = LocalDateTime.now().with(TemporalAdjusters.firstDayOfMonth()).toLocalDate().atStartOfDay();
    // 获取本月的结束时间，即最后一天 23:59:59
    LocalDateTime endTime = LocalDateTime.now().with(TemporalAdjusters.lastDayOfMonth())
            .toLocalDate().atTime(23, 59, 59);*/

    // 负载率,空负载率,作业效率
    List<BeltRoutePerformanceMonthRespVO> hour = baseMapper.getLineEfficiencyMonthS(routeId,startTime,endTime);
    List<LoadRateAndWorkingEfficiency> loadRateAndWorkingEfficiencies = hour.stream().map(h -> {
      LoadRateAndWorkingEfficiency loadRateAndWorkingEfficiency = new LoadRateAndWorkingEfficiency();
      loadRateAndWorkingEfficiency.setWorkEfficiency(h.getWorkEfficiency());
      loadRateAndWorkingEfficiency.setAvgNoLoadRate(h.getAvgNoLoadRate());
      loadRateAndWorkingEfficiency.setAvgLoadRate(h.getAvgLoadRate());
      loadRateAndWorkingEfficiency.setBelongDate(h.getBelongDate());
      return loadRateAndWorkingEfficiency;
    }).collect(Collectors.toList());
    lineEfficiencyMonth.setLoadRateAndWorkingEfficiencyList(loadRateAndWorkingEfficiencies);

    return lineEfficiencyMonth;
  }
  @Autowired
  private BasicDeviceMapper basicDeviceMapper;
  @Autowired
  private FlowBasicMapper flowBasicMapper;

  @Autowired
  private BeltPerformanceMonthMapper beltPerformancedMonthMapper;
  @Autowired
  private BeltRoutePerformanceMonthMapper beltRoutePerformanceMonthMapper;
    @Override
    public List<Map<String, Object>> getBeltInfoById(Long id) {
      // 根据 ID 查询 flow_basic 表
      FlowBasicRespVO flowBasic = flowBasicMapper.searchById(id);
      if (flowBasic == null) {
        return null;
      }

      // 将 flow_name 按下划线 _ 分割
      String flowName = flowBasic.getFlowName();
      List<String> beltNames = Arrays.asList(flowName.split("-"));

      // 根据 beltName 查询 basic_device 表
      List<BasicDevice> devices = basicDeviceMapper.selectByDeviceNames(beltNames);
      if (devices == null) {
        return null;
      }
      // 获取所有皮带的 ID
      List<Integer> beltIds = devices.stream()
              .map(BasicDevice::getId)
              .collect(Collectors.toList());

      // 统计所有皮带的总长度
      BigDecimal totalBeltLength = flowBasic.getFlowDistance();
      /*double totalBeltLength = devices.stream()
              .filter(device -> device != null && device.getDeviceLength() != null)
              .mapToDouble(device -> device.getDeviceLength().doubleValue())
              .sum();*/

      // 根据 beltId 查询 belt_performance_week 表
      List<BeltPerformanceMonthRespVO> performances = beltPerformancedMonthMapper.selectByBeltIds(beltIds);
      if (performances == null) {
        return null;
      }
      // 计算每条皮带的运输效率和运输能耗
      Map<Integer, BasicDevice> deviceMap = devices.stream()
              .collect(Collectors.toMap(BasicDevice::getId, device -> device));

      List<Map<String, Object>> result = performances.stream().map(performance -> {
        BasicDevice device = deviceMap.get(performance.getBeltId().intValue());
        if (device == null) {
          // 返回一个空的 Map 或者跳过当前项
          return new HashMap<String, Object>(); // 返回一个空的 Map
        }
        BigDecimal totalTransport = performance.getTotalTransport() == null ? BigDecimal.ZERO : performance.getTotalTransport();
        BigDecimal allRuntime = performance.getLoadRuntime() == null ? BigDecimal.ZERO : performance.getLoadRuntime();
        BigDecimal totalPowerConsumption = performance.getTotalPowerConsumption() == null ? BigDecimal.ZERO : performance.getTotalPowerConsumption();
        // 检查 totalTransport 和 allRuntime 是否为 null
        if (totalTransport == null || allRuntime == null) {
          log.error("totalTransport or allRuntime is null for beltId: {}", performance.getId());
          return null;
        }
        BigDecimal transportEfficiency = allRuntime.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : totalTransport.divide(allRuntime, 4, BigDecimal.ROUND_HALF_UP);
        BigDecimal transportEnergyConsumption = totalTransport.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : totalPowerConsumption.divide(totalTransport, 4, BigDecimal.ROUND_HALF_UP);

        return new HashMap<String, Object>() {{
          put("beltName", device.getDeviceName());
          put("beltLength", device.getDeviceLength());
          put("transportEfficiency", transportEfficiency);
          put("transportEnergyConsumption", transportEnergyConsumption);
        }};
      }).collect(Collectors.toList());

      // 获取整条线路的性能记录
      BeltRoutePerformanceMonthRespVO respVO = beltRoutePerformanceMonthMapper.searchById(id);
      if (respVO == null) {
        return null;
      }
      BigDecimal totalRouteTransport = respVO.getTotalTransport();
      //BigDecimal totalRouteRuntime = respVO.getAllRuntime();
      BigDecimal totalRouteRuntime = respVO.getLoadRuntime();
      BigDecimal totalRoutePowerConsumption = respVO.getTotalPowerConsumption();
       // 检查 totalRouteTransport 和 totalRouteRuntime 是否为 null
      if (totalRouteTransport == null || totalRouteRuntime == null) {
        log.error("totalRouteTransport or totalRouteRuntime is null for id: {}", id);
        return null;
      }
      BigDecimal routeTransportEfficiency = totalRouteRuntime.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : totalRouteTransport.divide(totalRouteRuntime, 4, BigDecimal.ROUND_HALF_UP);
      BigDecimal routeTransportEnergyConsumption = totalRouteTransport.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : totalRoutePowerConsumption.divide(totalRouteTransport, 4, BigDecimal.ROUND_HALF_UP);

      // 将总长度、整条线路的运输效率和运输能耗以及线路名称添加到结果中
      Map<String, Object> summary = new HashMap<>();
      summary.put("totalBeltLength", totalBeltLength);
      summary.put("routeTransportEfficiency", routeTransportEfficiency);
      summary.put("routeTransportEnergyConsumption", routeTransportEnergyConsumption);
      summary.put("flowName", flowName); // 添加整条线路的名称
      result.add(summary);

      return result;
    }


}
